﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Mengsk.ProxyDelivery.Domain;

namespace Mengsk.ProxyDelivery.Service
{
    /// <summary>
    /// 返回结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Result<T>
    {
        private const string NAME_ERROR = "error";
        private const string NAME_PAGEINDEX = "pageIndex";
        private const string NAME_TOTALNUMBER = "totalNumber";
        private const string NAME_DATAS = "objectList";

        public string Error { get; set; }

        public int PageIndex { get; set; }

        public int TotalNumber { get; set; }

        public List<T> Datas { get; private set; }

        public Result()
        {
            this.Datas = new List<T>();
        }

        public static bool IsBasicType(Type t)
        {
            if (t == typeof(Guid))
            {
                return true;
            }

            TypeCode tc = Type.GetTypeCode(t);
            return tc != TypeCode.Object;
        }

        public static object ParseBasicType(Type t, XElement x)
        {
            if (IsBasicType(t) == false)
            {
                throw new ArgumentException(t.FullName + " 不是基本类型");
            }
            object value = null;
            if (t == typeof(byte))
            {
                value = byte.Parse(x.Value.Trim());
            }
            else if (t == typeof(sbyte))
            {
                value = sbyte.Parse(x.Value.Trim());
            }
            else if (t == typeof(short))
            {
                value = short.Parse(x.Value.Trim());
            }
            else if (t == typeof(ushort))
            {
                value = ushort.Parse(x.Value.Trim());
            }
            else if (t == typeof(int))
            {
                value = int.Parse(x.Value.Trim());
            }
            else if (t == typeof(uint))
            {
                value = int.Parse(x.Value.Trim());
            }
            else if (t == typeof(long))
            {
                value = long.Parse(x.Value.Trim());
            }
            else if (t == typeof(ulong))
            {
                value = ulong.Parse(x.Value.Trim());
            }
            else if (t == typeof(float))
            {
                value = float.Parse(x.Value.Trim());
            }
            else if (t == typeof(double))
            {
                value = double.Parse(x.Value.Trim());
            }
            else if (t == typeof(decimal))
            {
                value = decimal.Parse(x.Value.Trim());
            }
            else if (t == typeof(DateTime))
            {
                value = DateTime.Parse(x.Value.Trim());
            }
            else if (t == typeof(Guid))
            {
                value = Guid.Parse(x.Value.Trim());
            }
            else if (t == typeof(string))
            {
                value = x.Value;
            }
            else if (t == typeof(byte[]))
            {
                value = Convert.FromBase64String(x.Value);
            }
            else if (t.BaseType != null && t.BaseType == typeof(Enum))
            {
                value = Enum.Parse(t, x.Value.Trim());
            }
            else if (t == typeof(bool))
            {
                value = Boolean.Parse(x.Value.Trim());
            }
            else
            {
                throw new Exception("不支持的未知类型" + t.FullName);
            }
            return value;
        }

        public static object ParseObject(Type t, XElement xe)
        {
            if (IsBasicType(t))
            {
                return ParseBasicType(t, xe);
            }

            //数据是复杂类型
            object obj = Activator.CreateInstance(t);
            var properties = t.GetProperties();
            var xGroups = xe.Elements().GroupBy(o => o.Name.LocalName);

            foreach (var group in xGroups)
            {
                PropertyInfo pi = properties.FirstOrDefault(o => o.Name.Equals(group.Key, StringComparison.OrdinalIgnoreCase));
                if (pi == null)
                {
                    Debug.WriteLine("未能在类型:" + typeof(T).FullName + " 找到属性:" + group.Key);
                    continue;
                }

                object value = null;
                Type pType = pi.PropertyType;
                if (IsBasicType(pType))
                {
                    value = ParseBasicType(pType, group.First());
                }
                else if (pi.PropertyType == typeof(byte[]))
                {
                    value = Convert.FromBase64String(group.First().Value);
                }
                else if (pi.PropertyType.BaseType != null && pi.PropertyType.BaseType == typeof(Array))
                {
                    Array array = (Array)Activator.CreateInstance(pi.PropertyType, group.Count());
                    string tmpType = pi.PropertyType.FullName.Replace("[]", "");
                    Type innerType = Type.GetType(tmpType, true);
                    for (int i = 0; i < array.Length; i++)
                    {
                        object o = ParseObject(innerType, group.ElementAt(i));
                        array.SetValue(o, i);
                    }
                    value = array;
                }
                else if (pi.PropertyType.IsGenericType && (pi.PropertyType.FullName.StartsWith("System.Collections.Generic.List") || pi.PropertyType.FullName.StartsWith("System.Collections.Generic.IList")))
                {
                    IList list = (IList)Activator.CreateInstance(pi.PropertyType);
                    foreach (var item in group)
                    {
                        object o = ParseObject(pi.PropertyType.GetGenericArguments()[0], item);
                        list.Add(o);
                    }
                    value = list;
                }
                else
                {
                    value = ParseObject(pi.PropertyType, group.First());
                }

                pi.SetValue(obj, value, null);
            }
            return obj;
        }

        public DataCollection<T> ToDataCollection()
        {
            DataCollection<T> collection = new DataCollection<T>();

            collection.Total = this.TotalNumber;

            foreach (var item in this.Datas)
            {
                collection.Add(item);
            }

            return collection;
        }

        public static Result<T> ParseXml(string xml)
        {
            Result<T> result = new Result<T>();
            XDocument xDoc = XDocument.Parse(xml);

            XElement xError = xDoc.Root.Element(NAME_ERROR);
            if (xError == null)
            {
                throw new Exception("解析结果文件失败，缺少元素:" + NAME_ERROR);
            }
            XElement xPageIndex = xDoc.Root.Element(NAME_PAGEINDEX);
            if (xPageIndex == null)
            {
                throw new Exception("解析结果文件失败，缺少元素:" + NAME_PAGEINDEX);
            }
            XElement xTotalNumber = xDoc.Root.Element(NAME_TOTALNUMBER);
            if (xTotalNumber == null)
            {
                throw new Exception("解析结果文件失败，缺少元素:" + NAME_TOTALNUMBER);
            }

            result.Error = xError.Value.Trim();
            result.PageIndex = int.Parse(xPageIndex.Value.Trim());
            result.TotalNumber = int.Parse(xTotalNumber.Value.Trim());

            XElement datas = xDoc.Root.Element(NAME_DATAS);
            if (datas == null)
            {
                return result;
            }

            foreach (XElement xe in datas.Elements())
            {
                object data = ParseObject(typeof(T), xe);
                result.Datas.Add((T)data);
            }
            return result;
        }
    }
}
